package nc.hrpbctp.control.bs.utils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import nc.bs.framework.common.NCLocator;
import nc.bs.framework.exception.ComponentException;
import nc.bs.logging.Logger;
import nc.bs.pf.pub.PfDataCache;
import nc.hrpbctp.control.pub.utils.BctpControlIdCodeCreator;
import nc.hrpbctp.control.pub.utils.BctpControlPubUtils;
import nc.impl.hrpbctp.busictrldim.busictrldim.BusiCtrlDimVOServiceImpl;
import nc.impl.pubapp.pattern.data.bill.BillQuery;
import nc.impl.pubapp.pattern.database.DataAccessUtils;
import nc.itf.uif.pub.IUifService;
import nc.pubitf.bbd.CurrtypeQuery;
import nc.pubitf.uapbd.CurrencyRateUtilHelper;
import nc.uif.pub.exception.UifException;
import nc.vo.bd.currtype.CurrtypeVO;
import nc.vo.bd.pub.EnableStateEnum;
import nc.vo.hrpbctp.busctrltype.BusictrlTypeVO;
import nc.vo.hrpbctp.busibillconfig.AggBusiConfigVO;
import nc.vo.hrpbctp.busibillconfig.BusiConfigDimmapVO;
import nc.vo.hrpbctp.busibillconfig.BusiConfigVO;
import nc.vo.hrpbctp.busictrl.AggBusiCtrlVO;
import nc.vo.hrpbctp.busictrl.BusiCtrlDataVO;
import nc.vo.hrpbctp.busictrl.BusiCtrlDetailVO;
import nc.vo.hrpbctp.busictrl.BusiCtrlRuleVO;
import nc.vo.hrpbctp.busictrl.BusiCtrlVO;
import nc.vo.hrpbctp.busictrldim.AggBusiCtrlDimVO;
import nc.vo.hrpbctp.busictrldim.BusiCtrlDimBVO;
import nc.vo.hrpbctp.busictrldim.BusiCtrlDimVO;
import nc.vo.hrpbctp.busictrlscheme.AggBusictrlSchemeVO;
import nc.vo.hrpbctp.busictrlscheme.BusictrlSchemeBVO;
import nc.vo.hrpbctp.busictrlscheme.BusictrlSchemeVO;
import nc.vo.hrpbctp.ctrldim.CtrlDimVO;
import nc.vo.hrpbctp.enums.BusiConfigTypeEnum;
import nc.vo.hrpbctp.enums.BusictrlOperationEnum;
import nc.vo.hrpbctp.enums.BusisceneEnum;
import nc.vo.hrpbctp.enums.BusisceneModeEnum;
import nc.vo.hrpbm.budgettype.Budgettype;
import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.BusinessException;
import nc.vo.pub.IVOMeta;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.billtype.BilltypeVO;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.AppContext;
import nc.vo.pubapp.pattern.data.IRowSet;
import nc.vo.pubapp.pattern.model.entity.bill.AbstractBill;
import nc.vo.pubapp.pattern.pub.MapList;
import nc.vo.pubapp.pattern.pub.SqlBuilder;
import nc.vo.pubapp.util.VOSortUtils;
import nccloud.commons.lang.StringUtils;

/**
 * 业务控制，后台工具类
 * @author WW
 *
 */
public class BctpControlBsUtils {

    /**
     * 查询业务单据配置VO
     * @param billtype
     * @param transtype
     * @param otherfilter
     * @return
     * @throws BusinessException
     */
    public static AggBusiConfigVO[] queryBusiConfig(String billtype,String transtype,String otherfilter) throws BusinessException{

        try {

            SqlBuilder sqlWhere = new SqlBuilder();

            sqlWhere.append(" select distinct ");
            sqlWhere.append(BusiConfigVO.getDefaultTableName());
            sqlWhere.append(".");
            sqlWhere.append(BusiConfigVO.PK_BUSICONFIG);
            sqlWhere.append(" from ");
            sqlWhere.append(BusiConfigVO.getDefaultTableName());

            sqlWhere.append(" where enablestate", EnableStateEnum.ENABLESTATE_ENABLE.toIntValue());

            //单据类型
            if(billtype != null && !"".contentEquals(billtype)) {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.BUSIBILLTYPE,billtype);
            }else {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.BUSIBILLTYPE);
                sqlWhere.append(" is null ");
            }
            //交易类型
            if(transtype != null && !"".contentEquals(transtype)) {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.BUSITRANSTYPE,transtype);
            }else {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.BUSITRANSTYPE);
                sqlWhere.append(" is null ");
            }

            //其他标识
            if(otherfilter != null && !"".contentEquals(otherfilter)) {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.OTHERFILTER,otherfilter);
            }else {
                sqlWhere.append(" and ");
                sqlWhere.append(BusiConfigVO.getDefaultTableName());
                sqlWhere.append(".");
                sqlWhere.append(BusiConfigVO.OTHERFILTER);
                sqlWhere.append(" is null ");
            }

            DataAccessUtils dao = new DataAccessUtils();
            IRowSet rowset = dao.query(sqlWhere.toString());
            String[] keys = rowset.toOneDimensionStringArray();


            BillQuery<AggBusiConfigVO> query = new BillQuery<AggBusiConfigVO>(AggBusiConfigVO.class);
            AggBusiConfigVO[] busiConfigVos = query.query(keys);

            busiConfigVos = busiConfigVos == null ? new AggBusiConfigVO[0] : busiConfigVos;

            return busiConfigVos;

        }catch(Exception e) {

            throw new BusinessException("查询业务单据配置错误："+ e.getMessage());

        }

    }

    /**
     *
     * 将参数单据数据按VO名称进行分组，方便取数（key：VO类名称）
     */
    public static MapList<String,SuperVO> getParamVoMap(AggBusiConfigVO aggBusiBillConfigVo,AggregatedValueObject paramVo) throws BusinessException{

        try {

            BusiConfigVO busiConfigVo = aggBusiBillConfigVo.getParentVO();

            String voName = paramVo.getParentVO().getClass().getSimpleName();
            MapList<String,SuperVO> paramVoMap = new MapList<String,SuperVO>();
            paramVoMap.put(voName, (SuperVO)paramVo.getParentVO());

            if(busiConfigVo.getBillbodyvomethod() == null || "".equals(busiConfigVo.getBillbodyvomethod())) {//没有指定获取明细数据的方法时直接取子表数据

                if(paramVo instanceof AbstractBill) {

                    AbstractBill paramVo_temp = (AbstractBill)paramVo;

                    IVOMeta[] metas = paramVo_temp.getMetaData().getChildren();

                    for(IVOMeta meta : metas) {

                        SuperVO[] childrens = (SuperVO[])paramVo_temp.getChildren(meta);

                        if(childrens != null) {

                            for(SuperVO children : childrens) {

                                //过滤掉状态为删除的VO
                                if(children.getStatus() == VOStatus.DELETED)
                                    continue;

                                voName = children.getClass().getSimpleName();

                                //只处理配置文件中设置表头和表体VO
                                if(voName.equals(busiConfigVo.getBillheadvoname()) || voName.equals(busiConfigVo.getBillbodyvoname())){
                                    paramVoMap.put(voName, children);
                                }

                            }

                        }

                    }

                } else {

                    SuperVO[] childrens = (SuperVO[])paramVo.getChildrenVO();

                    if(childrens != null) {

                        for(SuperVO children : childrens) {

                            //过滤掉状态为删除的VO
                            if(children.getStatus() == VOStatus.DELETED)
                                continue;

                            voName = children.getClass().getSimpleName();

                            //只处理配置文件中设置表头和表体VO
                            if(voName.equals(busiConfigVo.getBillheadvoname()) || voName.equals(busiConfigVo.getBillbodyvoname())){
                                paramVoMap.put(voName, children);
                            }

                        }

                    }

                }

            } else {//如果指定了获取明细数据的方法，则通过反射调用方法获取明细数据

                Method method = paramVo.getClass().getMethod(busiConfigVo.getBillbodyvomethod(), null);

                SuperVO[] paramDetialVos = (SuperVO[])method.invoke(paramVo, null);

                paramVoMap.putAll(busiConfigVo.getBillbodyvoname(), Arrays.asList(paramDetialVos));

            }

            return paramVoMap;


        }catch(Exception e) {
            throw new BusinessException(e.getMessage());
        }

    }

    /**
     * 获取新的控制信息
     * @return
     * @throws BusinessException
     */
    public static AggBusiCtrlVO getCtrlVoFromParam(AggBusiConfigVO aggBusiBillConfigVo,Map<String,BusiCtrlDimBVO> busiCtrlDimMap,Map<String,CtrlDimVO> ctrlDimMap, BusictrlSchemeVO ctrlScheme,BusictrlSchemeBVO ctrlSchemeb,AggregatedValueObject paramVo) throws BusinessException{

        try {

            if(paramVo == null)
                return null;

            BusiConfigVO busiConfigVo = aggBusiBillConfigVo.getParentVO();
            BusiConfigDimmapVO[] busiConfigDimMapVos = (BusiConfigDimmapVO[])aggBusiBillConfigVo.getChildren(BusiConfigDimmapVO.class);

            MapList<String,SuperVO> paramVoMap = getParamVoMap(aggBusiBillConfigVo, paramVo);

            SuperVO headVo = paramVoMap.get(busiConfigVo.getBillheadvoname()).get(0);
            List<SuperVO> bodyVos = paramVoMap.get(busiConfigVo.getBillbodyvoname());

            //ADD BY WW 2023-12-12 支持只有表头数据的情况
//			if(busiConfigVo.getBillheadvoname().equals(busiConfigVo.getBillbodyvoname())) {
//				bodyVos.add(headVo);
//			}

            if(bodyVos == null)
                bodyVos = new ArrayList<SuperVO>();

            BusiCtrlVO ctrlVo = getNewCtrlVo(null,busiConfigVo, ctrlScheme, headVo, bodyVos);

            //业务控制维度
            if(busiCtrlDimMap != null && busiCtrlDimMap.size() > 0) {
                String pk_ctrldim = busiCtrlDimMap.keySet().toArray(new String[0])[0];
                BusiCtrlDimBVO tempBusiCtrlDimBVo = busiCtrlDimMap.get(pk_ctrldim);

                ctrlVo.setPk_busictrldim(tempBusiCtrlDimBVo.getPk_busictrldim());

            }
            //业务控制方案:顺便赋值 业务场景和业务场景控制模式
            if(ctrlScheme != null) {
                ctrlVo.setPk_busictrlscheme(ctrlScheme.getPrimaryKey());

                ctrlVo.setBusiscene(ctrlScheme.getBusiscene());
                ctrlVo.setBusiscenemode(ctrlScheme.getBusiscenemode());

            }

            Object[] ctrlBodyVos =  getNewCtrlBodyVos(ctrlVo,busiConfigVo,busiConfigDimMapVos,busiCtrlDimMap, ctrlDimMap, ctrlScheme, ctrlSchemeb,headVo, bodyVos);
            BusiCtrlDataVO[] ctrlDataVos = (BusiCtrlDataVO[])ctrlBodyVos[0];
            BusiCtrlRuleVO[] ctrlRuleVos = (BusiCtrlRuleVO[])ctrlBodyVos[1];
            BusiCtrlDetailVO[] ctrlDetailVos = (BusiCtrlDetailVO[])ctrlBodyVos[2];

            AggBusiCtrlVO aggCtrlVo = new AggBusiCtrlVO();
            aggCtrlVo.setParentVO(ctrlVo);
            aggCtrlVo.setChildren(BusiCtrlDataVO.class, ctrlDataVos);
            aggCtrlVo.setChildren(BusiCtrlRuleVO.class, ctrlRuleVos);
            aggCtrlVo.setChildren(BusiCtrlDetailVO.class, ctrlDetailVos);

            return aggCtrlVo;

        }catch(Exception e) {
            throw new BusinessException(e.getMessage());
        }

    }

    /**
     * 获取执行的表头VO
     * @param topbusictrltypecode
     * @param busiConfigVo
     * @param ctrlScheme
     * @param headVo
     * @param bodyVoMap
     * @param paramVo
     * @return
     */
    public static BusiCtrlVO getNewCtrlVo(String topbusictrltypecode,BusiConfigVO busiConfigVo,BusictrlSchemeVO ctrlScheme,SuperVO headVo,List<SuperVO> bodyVos) throws BusinessException{

        /*
         * 进行取值转换
         */
        //如果是从子表取数，则取第一行
        SuperVO bodyVo = null;
        if(bodyVos != null && bodyVos.size() > 0) {
            bodyVo = bodyVos.get(0);
        }
        UFDateTime billcreatetimefield = (UFDateTime)getValue(busiConfigVo, headVo,bodyVo,busiConfigVo.getBillcreatetimefield(), "创建日期字段", false);;
        String pk_group = (String)getValue(busiConfigVo, headVo,bodyVo,busiConfigVo.getBillgroupfield(), "集团字段", false);
        String pk_org = (String)getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillorgfield(), "组织字段", false);

        BusiCtrlVO ctrlVo = new BusiCtrlVO();
        ctrlVo.setStatus(VOStatus.NEW);

        ctrlVo.setPk_group(pk_group);
        ctrlVo.setPk_org(pk_org);

//		ctrlVo.setCreationtime(AppContext.getInstance().getServerTime());
        ctrlVo.setCreationtime(billcreatetimefield);
        ctrlVo.setCreator(AppContext.getInstance().getPkUser());

        //年度
        Object year = getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillyearfield(), "年度字段", false).toString();
        if(year != null && !"".equals(year)) {
            ctrlVo.setNyear(year.toString().substring(0,4));
        }

        //项目
        ctrlVo.setPk_project(getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillprojectfield(), "项目字段", true).toString());

        BusictrlTypeVO topBudgetTypeVo = null;

        //控制单据
        if(BusiConfigTypeEnum.KZDJ.toStringValue().equals(busiConfigVo.getBusiconfigtype())) {

            /*
             * 业务控制类型
             * 部分控制单据可能无法从单据上获取业务控制类型字段
             * 此时先从控制方案中获取，如果获取不到则取方法入参的业务控制类型编码
             */
            if(ctrlScheme != null) {

                topBudgetTypeVo = queryTopBusictrlType(ctrlScheme.getPk_busictrltype());

            }else if(!StringUtils.isEmpty(topbusictrltypecode)){

                topBudgetTypeVo = queryTopBusictrlTypeByCode(topbusictrltypecode);

            }

            if(topBudgetTypeVo == null) {
                throw new BusinessException("以下信息取值为空，请检查：业务控制类型字段\n"+"提示：请检查业务单据配置或数据推送接口方法入参。");
            }

            /*
             * 特殊处理：2024-05-08 为了减少业务系统中控制规则和执行监控中联查部分预算业务信息，在此处记录以下业务信息
             * 医院预算模块：预算类型、编报科室、归口科室
             */
            if(busiConfigVo.getBusibilltype().startsWith("BM")){
                ctrlVo.setPk_budgettype(BctpControlPubUtils.getNotNullStrValue(headVo.getAttributeValue("pk_budgettype")));
                ctrlVo.setPk_budgetdept(BctpControlPubUtils.getNotNullStrValue(headVo.getAttributeValue("pk_budgetdept")));
                ctrlVo.setPk_updept(BctpControlPubUtils.getNotNullStrValue(headVo.getAttributeValue("pk_updept")));
            }

        }
        //受控单据（执行单据）
        else if(BusiConfigTypeEnum.SKDJ.toStringValue().equals(busiConfigVo.getBusiconfigtype())){

            //业务控制类型:执行的时候肯定是已经确认了业务控制类型之后才会走到这一步
            ctrlVo.setPk_topbusictrltype(ctrlScheme.getPk_busictrltype());
            //顶级业务控制类型
            topBudgetTypeVo = queryTopBusictrlType(ctrlVo.getPk_topbusictrltype());

        }

        //顶级业务控制类型
        ctrlVo.setPk_topbusictrltype(topBudgetTypeVo.getId());
        ctrlVo.setTopbusictrltypecode(topBudgetTypeVo.getCode());


        //业务控制单据类型
        ctrlVo.setBusibilltype(busiConfigVo.getBusibilltype());
        //业务控制单据交易类型
        ctrlVo.setBusitranstype((String)getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBilltranstypefield(), "业务单据交易类型字段", true));
        //业务控制单据主键
        ctrlVo.setBusibillid((String)getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillidfield(), "业务单据主键字段", false));
        //业务控制单据号
        ctrlVo.setBusibillno((String)getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillnofield(), "业务单据号字段", false));
        //业务单据日期
        Object busibilldate = getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBilldatefield(), "业务单据日期字段", false);
        ctrlVo.setBusibilldate(busibilldate == null ? null : new UFDate(busibilldate.toString()));
        //是否参与业务控制
        ctrlVo.setIsjoinctrl(UFBoolean.TRUE);


        //特殊处理：医院预算的业务科室预算编制数据不参与业务控制
        if(ctrlVo.getBusitranstype() != null && ctrlVo.getBusitranstype().startsWith("BM") && ctrlVo.getBusitranstype().indexOf("-BD") > 0) {
            ctrlVo.setIsjoinctrl(UFBoolean.FALSE);
        }

        return ctrlVo;
    }

    /**
     * 获取业务控制表体信息，包括控制规则、业务控制明细、业务控制执行明细
     * @param busiConfigVo
     * @param busiConfigDimMapVos
     * @param busiCtrlDimMap
     * @param ctrlDimMap
     * @param ctrlScheme
     * @param headVo
     * @param bodyVos
     * @return
     * @throws BusinessException
     */
    private static Object[] getNewCtrlBodyVos(BusiCtrlVO ctrlVo,BusiConfigVO busiConfigVo,BusiConfigDimmapVO[] busiConfigDimMapVos,Map<String,BusiCtrlDimBVO> busiCtrlDimMap,Map<String,CtrlDimVO> ctrlDimMap,BusictrlSchemeVO ctrlScheme,BusictrlSchemeBVO ctrlSchemeb,SuperVO headVo,List<SuperVO> bodyVos) throws BusinessException{

        List<BusiCtrlDataVO> ctrlDataVos = new ArrayList<BusiCtrlDataVO>();
        List<BusiCtrlRuleVO>  ctrlRuleVos = new ArrayList<BusiCtrlRuleVO>();
        List<BusiCtrlDetailVO>  ctrlDetailVos = new ArrayList<BusiCtrlDetailVO>();

        SuperVO bodyVo_0 = (bodyVos == null || bodyVos.size() == 0) ? null : bodyVos.get(0);

        String pk_group = (String)getValue(busiConfigVo, headVo,bodyVo_0,busiConfigVo.getBillgroupfield(), "集团字段", false);
        String pk_org = (String)getValue(busiConfigVo, headVo, bodyVo_0, busiConfigVo.getBillorgfield(), "组织字段", false);
        String userid = AppContext.getInstance().getPkUser();

        //将单据维度字段映射以控制维度档案主键转为Map
        Map<String,SuperVO> busiConfigDimMapVoMap = (Map<String,SuperVO>)BctpControlPubUtils.getVoMap(busiConfigDimMapVos, BusiConfigDimmapVO.PK_CTRLDIM);

        BusiCtrlDataVO tempCtrlData = null;
        BusiCtrlRuleVO tempCtrlRule = null;
        BusiCtrlDetailVO tempCtrlDetail = null;

        BusiCtrlDimBVO tempBusiCtrlDimVo;
        CtrlDimVO tempCtrlDimVo = null;
        BusiConfigDimmapVO tempConfigDimmapVo = null;


        Map<String,String> deptAndBudgetDeptMap = null;

        if(bodyVos != null){

            Object tempValue = null;
            Map<String,BusictrlTypeVO> busiCtrlTypeTopMap = new HashMap<String,BusictrlTypeVO>();
            BusictrlTypeVO topBusictrlTypeVO = null;
            for(SuperVO bodyVo : bodyVos) {

                //ADD BY WW 2024-08-23 如果单据中指定了业务控制类型，则只取本次执行的业务控制类型对应的数据
                if(BusiConfigTypeEnum.SKDJ.equalsValue(busiConfigVo.getBusiconfigtype())){
                    String pk_busibilltype = (String)getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBillbusictrltypefield(), "业务控制类型字段", true);

                    if(StringUtils.isNotEmpty(pk_busibilltype)){

                        topBusictrlTypeVO = busiCtrlTypeTopMap.get(pk_busibilltype);
                        if(pk_busibilltype != null) {
                            topBusictrlTypeVO = queryTopBusictrlType(pk_busibilltype);
                            busiCtrlTypeTopMap.put(pk_busibilltype,topBusictrlTypeVO);
                        }

                        if(topBusictrlTypeVO != null && !topBusictrlTypeVO.getId().equals(ctrlVo.getPk_topbusictrltype())){
                            continue;
                        }

                    }

                }


                tempValue = null;
                /*
                 * 处理控制数据
                 */
                tempCtrlData = new BusiCtrlDataVO();
                tempCtrlData.setStatus(VOStatus.NEW);
                tempCtrlData.setDr(0);

                tempCtrlData.setPk_group(pk_group);
                tempCtrlData.setPk_org(pk_org);

                //业务场景
                tempCtrlData.setBusiscene(ctrlVo.getBusiscene());
                //业务场景控制模式
                tempCtrlData.setBusiscenemode(ctrlVo.getBusiscenemode());
                //设置顶级业务控制类型编码
                tempCtrlData.setTopbusictrltypecode(ctrlVo.getTopbusictrltypecode());

                //维度编号
                tempValue = getValue(busiConfigVo, headVo, bodyVo, busiConfigVo.getBilldimnofield(), "维度编号字段", true).toString();
                tempCtrlData.setDimno(tempValue.toString());

                //从业务单据配置中获取单据类型
                BilltypeVO billtype = PfDataCache.getBillType(busiConfigVo.getBusibilltype());
                tempValue = billtype.getPk_billtypecode();
                tempCtrlData.setBusibilltype(tempValue.toString());
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBilltranstypefield(), "交易类型编码", true);
                BilltypeVO transtype = null;
                if(tempValue != null) {
                    transtype = PfDataCache.getBillType(tempValue.toString());
                    tempCtrlData.setBusitranstype(transtype.getPk_billtypecode());//交易类型编码
                }
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillidfield(), "单据主键", false);
                tempCtrlData.setBusibillid(tempValue.toString());//单据主键
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillbidfield(), "单据明细主键", false);
                tempCtrlData.setBusibillbid(tempValue.toString());//单据明细主键
                if(bodyVo != null) {//单据明细idcode(配合医院预算取历史数，先临时这样处理)
                    tempValue = bodyVo.getAttributeValue("idcode");
                    tempCtrlData.setBusibillidcode((String)tempValue);
                }

                //设置维度字段值
                for(String pk_ctrldim : busiCtrlDimMap.keySet()) {

                    tempValue = null;

                    //获取业务控制维度
                    tempBusiCtrlDimVo = busiCtrlDimMap.get(pk_ctrldim);

                    //获取控制维度档案
                    tempCtrlDimVo = ctrlDimMap.get(pk_ctrldim);

                    //获取单据维度字段映射
                    tempConfigDimmapVo = (BusiConfigDimmapVO)busiConfigDimMapVoMap.get(pk_ctrldim);

                    if(tempBusiCtrlDimVo.getIsallowedempty() != null && !tempBusiCtrlDimVo.getIsallowedempty().booleanValue() && tempConfigDimmapVo == null)
                        throw new BusinessException("以下控制维度未设置取值来源，请检查业务单据配置：\n"+tempCtrlDimVo.getName());

                    if(tempConfigDimmapVo != null) {
                        tempValue = getValue(busiConfigVo,headVo,bodyVo, tempConfigDimmapVo.getValuefield(), tempCtrlDimVo.getName(), true);
                    }


                    if(tempBusiCtrlDimVo.getIsallowedempty() != null && tempBusiCtrlDimVo.getIsallowedempty().booleanValue() == false && (tempValue == null || "".equals(tempValue))) {

                        //TODO 总账凭证特殊处理:维度为空时也不报错
                        //if(!"C0".equals(busiConfigVo.getBusibilltype())) {
                        throw new BusinessException("业务控制维度["+tempCtrlDimVo.getName()+"]不能为空，请检查。");
                        //}

                    }

                    //赋值控制维度字段
                    tempCtrlData.setAttributeValue(tempCtrlDimVo.getFieldcode(), tempValue);

                }

                /*
                 * 特殊处理：
                 * 1、处理年度
                 * 2、业务科室转换为对应的业务控制科室
                 */
                if(tempCtrlData.getDim1() != null && !"".equals(tempCtrlData.getDim1())) {
                    tempCtrlData.setDim1(tempCtrlData.getDim1().substring(0,4));
                }
//			if(BusiConfigTypeEnum.SKDJ.toString().equals(busiConfigVo.getBusiconfigtype())) {
//
//				if(deptAndBudgetDeptMap == null)
//					deptAndBudgetDeptMap = BctpControlBsUtils.queryDeptAndBudgetDeptMap(pk_group, pk_org, ctrlScheme.getNyear(), ctrlScheme.getPk_busictrltype(), null);
//
//					String pk_budgetdept = deptAndBudgetDeptMap.get(tempCtrlData.getDim2());
//
//					//总账凭证特殊处理:如果存在业务控制科室，则直接去业务控制科室，为空时也不报错
//					if("C0".equals(busiConfigVo.getBusibilltype())) {
//
//						Object pk_budgetdept_obj = bodyVo.getAttributeValue("pk_budgetdept");
//						if(pk_budgetdept_obj != null && !"".equals(pk_budgetdept_obj)) {
//							pk_budgetdept = pk_budgetdept_obj.toString();
//						}
//
//					}else {
//
//						if(pk_budgetdept == null || "".equals(pk_budgetdept)) {
//
//							if(pk_budgetdept == null || "".equals(pk_budgetdept)) {
//								Object deptname = getService().findColValue("org_dept", "name", "pk_dept = '"+tempCtrlData.getDim2()+"'");
//								throw new BusinessException("科室["+deptname+"]未进行业务控制科室对照，请检查。");
//							}
//
//						}
//
//					}
//
//					tempCtrlData.setDim2(pk_budgetdept);
//
//			}

                //设置控制数字段
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillmainnumfield(), "控制数", false);
                tempCtrlData.setControlamount(new UFDouble(tempValue.toString()));

                //设置期初执行数字段，如果有期初执行，则同时设置执行数
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillinitexecnumfield(), "期初执行数", true);
                if(tempValue == null || "".equals(tempValue))
                    tempValue = UFDouble.ZERO_DBL;

                tempCtrlData.setExecuteamount((UFDouble)tempValue);
                tempCtrlData.setInitexecuteamount((UFDouble)tempValue);

                ctrlDataVos.add(tempCtrlData);

                /*
                 *处理控制规则
                 */
                tempCtrlRule = new BusiCtrlRuleVO();
                tempCtrlRule.setStatus(VOStatus.NEW);
                tempCtrlRule.setDr(0);
                tempCtrlRule.setIdcode(tempCtrlData.getIdcode());


                tempCtrlRule.setControlmode(ctrlScheme.getControlmode());
                tempCtrlRule.setControlsymbol(ctrlScheme.getControlsymbol());
                tempCtrlRule.setControlrate(ctrlScheme.getControlrate());
                tempCtrlRule.setWarnrate(ctrlScheme.getWarnrate());

                //ADD BY WW 2023-11-10 设置预算状态：	启用
                tempCtrlRule.setPausestate(EnableStateEnum.ENABLESTATE_ENABLE.toIntValue());
                //ADD BY WW 2023-11-06 设置扩展维度值
                for(int m=1;m<=BctpControlIdCodeCreator.getDefdimLength();m++) {
                    String dimField = BctpControlIdCodeCreator.getDefdimFieldPreStr() + m;
                    tempCtrlRule.setAttributeValue(dimField, tempCtrlData.getAttributeValue(dimField));
                }

                ctrlRuleVos.add(tempCtrlRule);

                /*
                 * 处理执行明细
                 */
                tempCtrlDetail = new BusiCtrlDetailVO();
                tempCtrlDetail.setStatus(VOStatus.NEW);
                tempCtrlDetail.setDr(0);
                if(ctrlScheme != null)
                    tempCtrlDetail.setPk_busictrlscheme(ctrlScheme.getPk_busictrlscheme());//控制方案主键：用于引用校验
                if(ctrlSchemeb != null)
                    tempCtrlDetail.setPk_busictrlscheme_b(ctrlSchemeb.getPk_busictrlscheme_b());//控制方案明细主键：用于引用校验

                //设置维度值
                for(int m = 1;m<=BctpControlIdCodeCreator.getDimLength();m++) {
                    String dimField = BctpControlIdCodeCreator.getDimFieldPreStr() + m;
                    tempCtrlDetail.setAttributeValue(dimField, tempCtrlData.getAttributeValue(dimField));
                }
                //ADD BY WW 2023-11-06 设置扩展维度值
                for(int m=1;m<=BctpControlIdCodeCreator.getDefdimLength();m++) {
                    String dimField = BctpControlIdCodeCreator.getDefdimFieldPreStr() + m;
                    tempCtrlDetail.setAttributeValue(dimField, tempCtrlData.getAttributeValue(dimField));
                }


                tempCtrlDetail.setPk_group(pk_group);
                tempCtrlDetail.setPk_org(pk_org);
                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillidfield(), "单据主键", true);
                tempCtrlDetail.setPk_cdbillid(tempValue.toString());//单据主键

                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillnofield(), "单据号", true);
                tempCtrlDetail.setCdbillcode(tempValue.toString());//单据号

                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBilldatefield(), "单据日期", true);
                if(tempValue != null && !"".equals(tempValue))
                    tempCtrlDetail.setCdbilldate(new UFDate(tempValue.toString()));//时间：单据日期

                //从业务单据配置中获取单据类型
//			BilltypeVO billtype = PfDataCache.getBillType(busiConfigVo.getBusibilltype());
                tempValue = billtype.getPk_billtypecode();
                tempCtrlDetail.setCdbilltypecode(tempValue.toString());//单据类型编码

                tempValue = billtype.getPk_billtypeid();
                tempCtrlDetail.setPk_cdbilltype(billtype.getPk_billtypeid());//单据类型主键

                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBilltranstypefield(), "交易类型编码", true);
//			BilltypeVO transtype = null;
                if(tempValue != null) {
                    transtype = PfDataCache.getBillType(tempValue.toString());
                    tempCtrlDetail.setCdbilltranstype(transtype.getPk_billtypecode());//交易类型编码

                    tempCtrlDetail.setPk_cdtranstype(transtype.getPk_billtypeid());//交易类型主键
                }

                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillbidfield(), "单据明细主键", true);
                tempCtrlDetail.setPk_cdbillbid(tempValue.toString());//单据明细主键

                tempValue = getValue(busiConfigVo,headVo,bodyVo, busiConfigVo.getBillrownofield(), "单据明细行号", true);
                tempCtrlDetail.setCdrowno(tempValue.toString());//单据明细行号


                tempCtrlDetail.setExecuserid(userid);//操作人
                tempCtrlDetail.setExectime(AppContext.getInstance().getServerTime());//操作时间：当前服务器时间
                tempCtrlDetail.setAmount(tempCtrlData.getControlamount());//金额
                tempCtrlDetail.setExecuteamount(tempCtrlData.getExecuteamount());//执行金额：主要用于处理期初执行
                tempCtrlDetail.setCdopt(null);//业务控制执行操作:：在具体操作时进行赋值
                tempCtrlDetail.setCdbillaction(null);//单据操作：在具体操作时进行赋值

                tempCtrlDetail.setPk_busictrl(null);//控制信息主键：在具体操作时进行赋值
                tempCtrlDetail.setPk_busictrldata(null);//控制数据主键：在具体操作时进行赋值
                tempCtrlDetail.setIdcode(tempCtrlData.getIdcode());//唯一标识码

                ctrlDetailVos.add(tempCtrlDetail);

            }
        }


        //ADD BY WW 2024-08-16 控制单据默认不生成执行明细
        if(BusiConfigTypeEnum.KZDJ.equalsValue(busiConfigVo.getBusiconfigtype())){
            ctrlDetailVos.clear();
        }

        return new Object[]{ctrlDataVos.toArray(new BusiCtrlDataVO[0]), ctrlRuleVos.toArray(new BusiCtrlRuleVO[0]), ctrlDetailVos.toArray(new BusiCtrlDetailVO[0])};

    }

    /**
     * 从参数VO中获取对应字段的值
     * @param paramVo
     * @param valueField
     * @param fieldName
     * @param isAllowedEmpty
     * @return
     * @throws BusinessException
     */
    public static Object getValue(BusiConfigVO busiConfigVo,SuperVO headVo,SuperVO bodyVo,String valueField,String fieldName,boolean isAllowedEmpty) throws BusinessException{

        if((valueField == null || "".equals(valueField) || "@".equals(valueField)) && isAllowedEmpty == true) {
            return "";
        }

        if((valueField == null || "".equals(valueField) || "@".equals(valueField)) && isAllowedEmpty == false) {
            throw new BusinessException("以下信息未设置取值来源，请检查业务单据配置：\n"+fieldName+"("+valueField+")");
        }
        Object value = null;

        if(valueField.startsWith("$")) {

            value = valueField.substring(1);

        }else {

            //有多个取值字段时，递归调用取值方法，直到取到非空的值
            String[] valueFields = valueField.split(",");
            if(valueFields.length > 1) {
                for(String splitValueField : valueFields) {

                    String[] fieldStr = splitValueField.split("\\.");
                    if(fieldStr == null || fieldStr.length != 2) {
                        throw new BusinessException("以下信息取值来源设置错误，正确格式为#VO类名.字段名#，请检查业务单据配置：\n"+fieldName+"("+valueField+")");
                    }

                    value = getValue(busiConfigVo, headVo, bodyVo, splitValueField, fieldName, true);

                    if(value != null && !"".equals(value)) {
                        return value;
                    }

                }
            }else{
                String[] fieldStr = valueField.split("\\.");
                if(fieldStr == null || fieldStr.length != 2) {
                    throw new BusinessException("以下信息取值来源设置错误，正确格式为#VO类名.字段名#，请检查业务单据配置：\n"+fieldName+"("+valueField+")");
                }
                if(busiConfigVo.getBillheadvoname().equals(fieldStr[0]) && headVo != null){
                    value = headVo.getAttributeValue(fieldStr[1]);
                }else if(busiConfigVo.getBillbodyvoname().equals(fieldStr[0]) && bodyVo != null){
                    value = bodyVo.getAttributeValue(fieldStr[1]);
                    if(value == null && "amount".equals(fieldStr[1])) {
                        value = bodyVo.getAttributeValue("amount_firstup");
                    }
                }else if(BusiCtrlVO.class.getSimpleName().equals(fieldStr[0]) && headVo != null) {
                    value = headVo.getAttributeValue(fieldStr[1]);
                }
            }

//			String[] fieldStr = valueField.split("\\.");
//			if(fieldStr == null || fieldStr.length != 2) {
//				throw new BusinessException("以下信息取值来源设置错误，正确格式为#VO类名.字段名#，请检查业务单据配置：\n"+fieldName+"("+valueField+")");
//			}

//			if(busiConfigVo.getBillheadvoname().equals(fieldStr[0]) && headVo != null){
//				value = headVo.getAttributeValue(fieldStr[1]);
//			}else if(busiConfigVo.getBillbodyvoname().equals(fieldStr[0]) && bodyVo != null){
//				value = bodyVo.getAttributeValue(fieldStr[1]);
//			}else if(BusiCtrlVO.class.getSimpleName().equals(fieldStr[0]) && headVo != null) {
//				value = headVo.getAttributeValue(fieldStr[1]);
//			}

        }

        if((value == null || "".equals(value)) && isAllowedEmpty == false) {
            throw new BusinessException("以下信息取值为空，请检查：\n"+fieldName+"("+valueField+")");
        }

        value = value == null ? "" : value;

        return value;

    }


    /**
     * 从参数VO中获取对应字段不重复的值
     * @param paramVo
     * @param valueField
     * @param fieldName
     * @param isAllowedEmpty
     * @return
     * @throws BusinessException
     */
    public static String[] getUniqualValues(BusiConfigVO busiConfigVo,SuperVO headVo,List<SuperVO> bodyVos,String valueField,String fieldName,boolean isAllowedEmpty) throws BusinessException{

        Set<String> valueSet = new HashSet<String>();
        Object tempValue = null;

        if(bodyVos != null && bodyVos.size() > 0) {
            for(int i=0;i<bodyVos.size();i++) {

                tempValue = getValue(busiConfigVo, headVo, bodyVos.get(i), valueField, fieldName, isAllowedEmpty);

                if(tempValue != null)
                    valueSet.add(tempValue.toString());

            }
        }else {

            tempValue = getValue(busiConfigVo, headVo, null, valueField, fieldName, isAllowedEmpty);

            if(tempValue != null)
                valueSet.add(tempValue.toString());

        }

        return valueSet.toArray(new String[0]);

    }

    /**
     * 查询部门-归口科室映射关系
     * @param pk_group
     * @param pk_org
     * @param year
     * @return
     * @throws BusinessException
     */
//	public static Map<String,String> queryDeptAndBudgetDeptMap(String pk_group,String pk_org,String year,String pk_budgettype,String[] pk_depts) throws BusinessException{
//
//		SqlBuilder wherePart = new SqlBuilder();
//		wherePart.append(" dr = 0");
//		wherePart.append(" and pk_group", pk_group);
//		wherePart.append(" and pk_org", pk_org);
//		wherePart.append(" and nyear", year);
//		wherePart.append(" and pk_budgettype",pk_budgettype);
//		if(pk_depts != null)
//		wherePart.append(" and pk_dept", pk_depts);
//
//		//TODO
//		BudgetDeptMapVO[] deptMapVos = (BudgetDeptMapVO[])getService().queryByCondition(BudgetDeptMapVO.class, wherePart.toString());
//
//		Map<String,String> deptAndBudgetDeptMap = new HashMap<String,String>();
//
//		if(deptMapVos != null) {
//			for(int i=0;i<deptMapVos.length;i++) {
//
//				if(deptAndBudgetDeptMap.containsKey(deptMapVos[i].getPk_dept())) {
//					throw new BusinessException("科室#"+deptMapVos[i].getPk_dept()+"#对应了多个业务控制科室，请检查。");
//				}
//
//				deptAndBudgetDeptMap.put(deptMapVos[i].getPk_dept(), deptMapVos[i].getPk_budgetdept());
//
//			}
//
//		}
//
//		return deptAndBudgetDeptMap;
//
//	}

    /**
     * 查询业务控制类型对应的业务控制方案
     * 为了推送业务控制时获取默认的业务控制方式、控制比例等信息
     * @param busiscene
     * @param busiscenemode
     * @param pk_group
     * @param pk_org
     * @param year
     * @param pk_topbusictrltype
     * @return
     * @throws BusinessException
     */
    public static BusictrlSchemeVO queryCtrlSchemeForPushData(String busiscene,String busiscenemode,String pk_group,String pk_org,String year,String pk_topbusictrltype) throws BusinessException{

        //查询当前业务控制类型下所有启用的业务控制方案
        SqlBuilder wherePart = new SqlBuilder();
        wherePart.append(" dr = 0");
        wherePart.append(" and busiscene", busiscene);
        wherePart.append(" and busiscenemode", busiscenemode);
        wherePart.append(" and enablestate", EnableStateEnum.ENABLESTATE_ENABLE.toIntValue());
        wherePart.append(" and pk_busictrltype",pk_topbusictrltype);

        BusictrlSchemeVO[] ctrlSchemes = (BusictrlSchemeVO[])getService().queryByCondition(BusictrlSchemeVO.class, wherePart.toString());

        if(ctrlSchemes == null || ctrlSchemes.length == 0) {
//			throw new BusinessException("未查询到启用的业务控制方案！");
            return null;
        }

        BusictrlSchemeVO matchedCtrlScheme = matchCtrlScheme(pk_group, pk_org, year, ctrlSchemes);

        if(matchedCtrlScheme == null) {
//			throw new BusinessException("未匹配到启用的业务控制方案！");
            return null;
        }


        return matchedCtrlScheme;

    }

    /**
     * 查询受控单据启用的业务控制方案
     * 为了判断是否需要进行业务控制，并控制那种类型的业务控制
     * @param busiscene
     * @param busiscenemode
     * @param pk_group
     * @param pk_org
     * @param year
     * @param billtype
     * @param transtype
     * @param busictrltypeCodes
     * @return
     * @throws BusinessException
     */
    public static AggBusictrlSchemeVO[] queryCtrlSchemeForControl(String busiscene,String busiscenemode,String pk_group,String pk_org,String year,String billtype,String transtype,String[] busictrltypeCodes) throws BusinessException{

        //先按照交易类型、单据类型匹配预算控制方案明细
        SqlBuilder wherePart = new SqlBuilder();
        wherePart.append(" dr = 0");
//		wherePart.append(" and isusing = 'Y'");
        wherePart.append(" and billtypecode",billtype);
        wherePart.append(" and pk_busictrlscheme in (");
        wherePart.append(" select pk_busictrlscheme from hrpbctp_busictrlscheme");
        wherePart.append(" where dr = 0");
        wherePart.append(" and busiscene", busiscene);
        wherePart.append(" and busiscenemode", busiscenemode);
//		wherePart.append(" and enablestate", EnableStateEnum.ENABLESTATE_ENABLE.toIntValue());
        //如果指定了需要执行的业务控制类型，则加入到查询条件中
        if(busictrltypeCodes != null && busictrltypeCodes.length > 0) {
            wherePart.append(" and pk_busictrltype in (");
            wherePart.append(" select id from hrpbctp_busictrltype where dr = 0 and code",busictrltypeCodes);
            wherePart.append(" ) ");
        }
        wherePart.append(")");

        BusictrlSchemeBVO[] ctrlSchemeDetails = (BusictrlSchemeBVO[])getService().queryByCondition(BusictrlSchemeBVO.class, wherePart.toString());

        Set<String> matchSchemeIds = new HashSet<String>();
        Map<String,BusictrlSchemeBVO> matchedCtrlSchemeBvoMap = new HashMap<String,BusictrlSchemeBVO>();//记录匹配到的控制方案：理论上只会有一个
        if(ctrlSchemeDetails != null && ctrlSchemeDetails.length > 0) {

            //根据交易类型匹配的控制方案主键
            for(BusictrlSchemeBVO ctrlSchemeDetail : ctrlSchemeDetails) {

                //控制方案中交易类型为空
                if(ctrlSchemeDetail.getTranstypecode() == null ||  "".equals(ctrlSchemeDetail.getTranstypecode())){

                    matchSchemeIds.add(ctrlSchemeDetail.getPk_busictrlscheme());
                    matchedCtrlSchemeBvoMap.put(ctrlSchemeDetail.getPk_busictrlscheme(), ctrlSchemeDetail);

                }
                //交易类型完全匹配
                else if(transtype != null && !"".equals(transtype)) {

                    //控制方案的交易类型为多选，此处处理一下
                    List<String> ctrlScheme_transttypecodes = Arrays.asList(ctrlSchemeDetail.getTranstypecode().split(","));

                    if(ctrlScheme_transttypecodes.contains(transtype)) {

                        matchSchemeIds.add(ctrlSchemeDetail.getPk_busictrlscheme());
                        matchedCtrlSchemeBvoMap.put(ctrlSchemeDetail.getPk_busictrlscheme(), ctrlSchemeDetail);

                    }

                }

            }

        }

        if(matchSchemeIds.size() > 0) {

            wherePart = new SqlBuilder();
            wherePart.append(" pk_busictrlscheme ",matchSchemeIds.toArray(new String[0]));
            BusictrlSchemeVO[] ctrlSchemes = (BusictrlSchemeVO[])getService().queryByCondition(BusictrlSchemeVO.class, wherePart.toString());

            if(ctrlSchemes == null || ctrlSchemes.length == 0) {
                return null;
//				throw new BusinessException("未查询到业务控制方案！");
            }

            ctrlSchemes = matchCtrlSchemes(pk_group,pk_org, year, ctrlSchemes);

            List<AggBusictrlSchemeVO> matchedCtrlSchemes = new ArrayList<AggBusictrlSchemeVO>();
            AggBusictrlSchemeVO tempMatchedCtrlScheme = null;
            if(ctrlSchemes != null && ctrlSchemes.length > 0) {


                for(int i=0;i<ctrlSchemes.length;i++) {

                    tempMatchedCtrlScheme = new AggBusictrlSchemeVO();

                    tempMatchedCtrlScheme.setParentVO(ctrlSchemes[i]);
                    tempMatchedCtrlScheme.setChildren(BusictrlSchemeBVO.class, new BusictrlSchemeBVO[] {matchedCtrlSchemeBvoMap.get(ctrlSchemes[i].getPk_busictrlscheme())});

                    /*
                     * 过滤掉未启用的控制方案
                     * 不能直接在查询条件中过滤掉未启用的控制方案，因为存在下面这种场景
                     * 匹配到了组织级未启用的业务控制方案，此时不应该再匹配到集团或者全局级启用的控制方案，所以要允许匹配未启用的方案，最后再将匹配到的未启用的控制方案过滤掉
                     */
                    BusictrlSchemeVO ctrlScheme = tempMatchedCtrlScheme.getParentVO();
                    BusictrlSchemeBVO ctrlSchemeb = (BusictrlSchemeBVO)tempMatchedCtrlScheme.getAllChildrenVO()[0];

                    if(ctrlScheme.getEnablestate() != EnableStateEnum.ENABLESTATE_ENABLE.toIntValue()
                            || ctrlSchemeb.getIsusing() == null || ctrlSchemeb.getIsusing().booleanValue() == false) {
                        continue;
                    }

                    matchedCtrlSchemes.add(tempMatchedCtrlScheme);

                }

            }

            return matchedCtrlSchemes.toArray(new AggBusictrlSchemeVO[0]);

        }

        return null;

    }

    /**
     * 匹配业务控制方案
     * @param pk_group
     * @param year
     * @param ctrlSchemes
     * @return
     * @throws BusinessException
     */
    private static BusictrlSchemeVO[] matchCtrlSchemes(String pk_group,String pk_org,String year,BusictrlSchemeVO[] ctrlSchemes) throws BusinessException{

        List<BusictrlSchemeVO> matchedCtrlSchemeList = new ArrayList<BusictrlSchemeVO>();

        MapList<String,SuperVO> ctrlSchemeVoMapList = BctpControlPubUtils.getVoMapList(ctrlSchemes, BusictrlSchemeVO.PK_BUSICTRLTYPE);

        for(String key : ctrlSchemeVoMapList.keySet()) {

            BusictrlSchemeVO[] tempCtrlSchemes = ctrlSchemeVoMapList.get(key).toArray(new BusictrlSchemeVO[0]);

            BusictrlSchemeVO matchedCtrlScheme = matchCtrlScheme(pk_group, pk_org,year, tempCtrlSchemes);

            if(matchedCtrlScheme != null)
                matchedCtrlSchemeList.add(matchedCtrlScheme);

        }

        if(matchedCtrlSchemeList.size() == 0) {
            return null;
//			throw new BusinessException("未匹配到业务控制方案，请检查！");
        }

        return matchedCtrlSchemeList.toArray(new BusictrlSchemeVO[0]);

    }

    /**
     * 匹配业务控制方案，只匹配同一中业务控制类型控制方案
     * @param pk_group
     * @param year
     * @param ctrlSchemes
     * @return
     * @throws BusinessException
     */
    private static BusictrlSchemeVO matchCtrlScheme(String pk_group,String pk_org,String year,BusictrlSchemeVO[] ctrlSchemes) throws BusinessException{

        /*
         * 目前业务控制方案为业务控制全局+集团级
         * 将全集、集团下所有当前业务控制类型下启用的业务控制方案都查询出来然后按照以下顺序进行匹配
         * 年度可以为空
         * 1、组织+年度
         * 2、组织
         * 3、集团+年度
         * 4、集团
         * 5、全局+年度
         * 6、全局
         */
        //按照优先级进行匹配
        String[] matchKeys = new String[] {
                pk_org + BctpControlPubUtils.getNotNullStrValue(year),
                pk_org,
                pk_group + BctpControlPubUtils.getNotNullStrValue(year),
                pk_group,
                "GLOBLE00000000000000" + BctpControlPubUtils.getNotNullStrValue(year),
                "GLOBLE00000000000000",
        };


        Map<String,BusictrlSchemeVO> ctrlSchemeMatchKeyMap = new HashMap<String,BusictrlSchemeVO>();
        for(BusictrlSchemeVO ctrlScheme : ctrlSchemes) {

            String matchKey = ctrlScheme.getPk_org() + BctpControlPubUtils.getNotNullStrValue(ctrlScheme.getNyear());

//			if(ctrlSchemeMatchKeyMap.containsKey(matchKey))
//				throw new BusinessException("同一业务控制类型下匹配到多个启用的业务控制方案，请检查！");

            ctrlSchemeMatchKeyMap.put(matchKey, ctrlScheme);

        }

        BusictrlSchemeVO matchedCtrlScheme = null;

        for(String matchKey : matchKeys) {

            if(matchedCtrlScheme == null) {

                matchedCtrlScheme = ctrlSchemeMatchKeyMap.get(matchKey);
                if(matchedCtrlScheme != null) {
                    break;
                }

            }

        }

        return matchedCtrlScheme;

    }

    /**
     * 查询业务控制维度中启用的维度信息
     * @param busiscene
     * @param busiscenemode
     * @param pk_group
     * @param pk_org
     * @param year
     * @param billtype
     * @param transtype
     * @param pk_busictrltype
     * @return
     * @throws BusinessException
     */
    public static AggBusiCtrlDimVO queryBusiCtrlDim(String busiscene,String busiscenemode,String pk_group,String pk_org,String year,String pk_busictrltype) throws BusinessException{

        //查询当前业务控制类型下所有启用的业务控制维度
        SqlBuilder wherePart = new SqlBuilder();
        wherePart.append(" dr = 0");
        wherePart.append(" and busiscene", busiscene);
        wherePart.append(" and busiscenemode", busiscenemode);
        wherePart.append(" and enablestate", EnableStateEnum.ENABLESTATE_ENABLE.toIntValue());
        wherePart.append(" and pk_busictrltype", pk_busictrltype);

        AggBusiCtrlDimVO[] aggBusiCtrlDimVos = new BusiCtrlDimVOServiceImpl().listAggBusiCtrlDimVOByCondition(wherePart.toString());

        if(aggBusiCtrlDimVos == null || aggBusiCtrlDimVos.length == 0) {
            throw new BusinessException("未查询到启用的业务控制维度！");
        }

        Map<String,AggBusiCtrlDimVO> matchedaggBusiCtrlDimVoMatchKeyMap = new HashMap<String,AggBusiCtrlDimVO>();
        for(AggBusiCtrlDimVO aggBusiCtrlDimVo : aggBusiCtrlDimVos) {

            BusiCtrlDimVO busiCtrlDimVo= aggBusiCtrlDimVo.getParentVO();

            String matchKey = busiCtrlDimVo.getPk_org() + BctpControlPubUtils.getNotNullStrValue(busiCtrlDimVo.getNyear());

            if(matchedaggBusiCtrlDimVoMatchKeyMap.containsKey(matchKey))
                throw new BusinessException("匹配到多条启用的业务控制维度！");

            matchedaggBusiCtrlDimVoMatchKeyMap.put(matchKey, aggBusiCtrlDimVo);

        }

        AggBusiCtrlDimVO matchedaggBusiCtrlDimVo = null;
        //按照优先级进行匹配
        String[] matchKeys = new String[] {
                pk_org + BctpControlPubUtils.getNotNullStrValue(year),
                pk_org,
                pk_group + BctpControlPubUtils.getNotNullStrValue(year),
                pk_group,
                "GLOBLE00000000000000" + BctpControlPubUtils.getNotNullStrValue(year),
                "GLOBLE00000000000000",
        };
        for(String matchKey : matchKeys) {

            if(matchedaggBusiCtrlDimVo == null) {

                matchedaggBusiCtrlDimVo = matchedaggBusiCtrlDimVoMatchKeyMap.get(matchKey);

                if(matchedaggBusiCtrlDimVo != null)
                    break;

            }
        }


        if(matchedaggBusiCtrlDimVo == null)
            throw new BusinessException("未匹配到启用的业务控制维度！");

        List<BusiCtrlDimBVO> busiCtrlDimBVos = new ArrayList<BusiCtrlDimBVO>();

        for(BusiCtrlDimBVO bsd : (BusiCtrlDimBVO[])matchedaggBusiCtrlDimVo.getChildrenVO()) {

            if(bsd.getIsusing() != null && bsd.getIsusing().booleanValue())
                busiCtrlDimBVos.add(bsd);

        }

        //按照业务控制方案中的行号进行排序
        VOSortUtils.ascSort(busiCtrlDimBVos, new String[] {BusiCtrlDimBVO.ROWNO});

        matchedaggBusiCtrlDimVo.setChildrenVO(busiCtrlDimBVos.toArray(new BusiCtrlDimBVO[0]));

        return matchedaggBusiCtrlDimVo;

    }

    /**
     * 查询业务控制维度对应的控制维度档案
     * @param aggBusiCtrlDimVO
     * @throws BusinessException
     */
    public static CtrlDimVO[] queryCtrlDims(BusiCtrlDimBVO[] busiCtrlDims) throws BusinessException{

        CtrlDimVO[] ctrlDims = null;

        if(busiCtrlDims != null) {

            ctrlDims = new CtrlDimVO[busiCtrlDims.length];

            for(int i=0;i<busiCtrlDims.length;i++) {

                ctrlDims[i] = getCtrlDimVo(busiCtrlDims[i].getPk_ctrldim());

            }

        }

        return ctrlDims;

    }

    private static Map<String,CtrlDimVO> ctrlDimMap = new HashMap<String,CtrlDimVO>();
    private static CtrlDimVO getCtrlDimVo(String pk_ctrldim) throws BusinessException	{

        CtrlDimVO ctrlDimVo = ctrlDimMap.get(pk_ctrldim);

        if(ctrlDimVo == null) {

            ctrlDimVo = (CtrlDimVO)getService().queryByPrimaryKey(CtrlDimVO.class, pk_ctrldim);

            ctrlDimMap.put(pk_ctrldim, ctrlDimVo);

        }

        return ctrlDimVo;

    }

    /**
     * 合并执行明细
     * 按照执行单据的明细进行vo合并
     * @param ctrlDetailList
     * @return
     * @throws BusinessException
     */
    public static BusiCtrlDetailVO[] combineCtrlDetail(List<BusiCtrlDetailVO> ctrlDetailList) throws BusinessException{

        Map<String,BusiCtrlDetailVO> combineDetailMap = new HashMap<String,BusiCtrlDetailVO>();

        BusiCtrlDetailVO tempDetailVo = null;
        BusiCtrlDetailVO tempCombineVo = null;
        UFDouble amount = null;
        UFDouble preoccuamount = null;
        UFDouble executeamount = null;
        UFDouble amount_combine = null;
        UFDouble preoccuamount_combine = null;
        UFDouble executeamount_combine = null;
        String key = null;
        for(int i=0;i<ctrlDetailList.size();i++) {

            tempDetailVo = ctrlDetailList.get(i);
            key = tempDetailVo.getIdcode() + tempDetailVo.getPk_cdbillid() + tempDetailVo.getPk_cdbillbid();

            tempCombineVo = combineDetailMap.get(key);

            if(tempCombineVo == null) {

                tempCombineVo = (BusiCtrlDetailVO)tempDetailVo.clone();

            }else {

                //取执行明细金额
                amount = tempDetailVo.getAmount();
                preoccuamount = tempDetailVo.getPreoccuamount();
                preoccuamount = preoccuamount == null ? UFDouble.ZERO_DBL : preoccuamount;
                executeamount = tempDetailVo.getExecuteamount();
                executeamount = executeamount == null ? UFDouble.ZERO_DBL : executeamount;
                //取合并记录金额
                amount_combine = tempCombineVo.getAmount();
                preoccuamount_combine = tempCombineVo.getPreoccuamount();
                preoccuamount_combine = preoccuamount_combine == null ? UFDouble.ZERO_DBL : preoccuamount_combine;
                executeamount_combine = tempCombineVo.getExecuteamount();
                executeamount_combine = executeamount_combine == null ? UFDouble.ZERO_DBL : executeamount_combine;

                //计算合并金额
                amount_combine = amount_combine.add(amount);
                preoccuamount_combine = preoccuamount_combine.add(preoccuamount);
                executeamount_combine = executeamount_combine.add(executeamount);

                //金额为0时，置空
                preoccuamount_combine = preoccuamount_combine.compareTo(UFDouble.ZERO_DBL) == 0 ? null : preoccuamount_combine;
                executeamount_combine = executeamount_combine.compareTo(UFDouble.ZERO_DBL) == 0 ? null : executeamount_combine;

                //重新赋值
                tempCombineVo.setAmount(amount_combine);
                tempCombineVo.setPreoccuamount(preoccuamount_combine);
                tempCombineVo.setExecuteamount(executeamount_combine);


                //赋值业务控制操作
                String cdoptname = BusictrlOperationEnum.getShowName(tempDetailVo.getCdopt());

//				tempCombineVo.setCdopt(tempCombineVo.getCdopt() + "," + tempDetailVo.getCdopt());
                tempCombineVo.setCdopt(null);
                tempCombineVo.setCdoptname(tempCombineVo.getCdoptname() + "," + cdoptname);

            }


            combineDetailMap.put(key, tempCombineVo);

        }

        return combineDetailMap.values().toArray(new BusiCtrlDetailVO[0]);

    }

    public static Map<String,CtrlDimVO> dimVoMap = new HashMap<String,CtrlDimVO>();
    /**
     * 获取维度定义
     * @param pk_budgetdim
     * @throws BusinessException
     */
//	private static CtrlDimVO getDimeVO(String pk_ctrldim) throws BusinessException{
//
//		if(dimVoMap.size() == 0) {
//			CtrlDimVO[] dimVos = (CtrlDimVO[])getService().queryByCondition(CtrlDimVO.class, "dr = 0");
//
//			if(dimVos!= null && dimVos.length > 0) {
//				dimVoMap = new HashMap<String,CtrlDimVO>();
//
//				for(int i=0;i<dimVos.length;i++) {
//					dimVoMap.put(dimVos[i].getPrimaryKey(), dimVos[i]);
//				}
//
//			}
//
//		}
//
//		CtrlDimVO dimensionVO = dimVoMap.get(pk_ctrldim);
//
//		if(dimensionVO == null) {
//			throw new BusinessException("未获取到对应的业务控制维度。");
//		}
//
//		return dimensionVO;
//
//	}

    /**
     * 查询业务控制类型对应的顶级业务控制类型编码
     * @param pk_busictrltype
     * @return
     * @throws BusinessException
     */
    public static BusictrlTypeVO queryTopBusictrlType(String pk_busictrltype) throws BusinessException{

        String topInnercode = null;
        //先查预算类型
        Budgettype budgettype = (Budgettype)getService().queryByPrimaryKey(Budgettype.class, pk_busictrltype);
        if(budgettype != null){
            topInnercode = budgettype.getInnercode().substring(0,4);
        }
        //再查业务控制类型
        else{
            BusictrlTypeVO bysiCtrlTypeVo = (BusictrlTypeVO)getService().queryByPrimaryKey(BusictrlTypeVO.class, pk_busictrltype);
            if(bysiCtrlTypeVo != null){
                topInnercode = bysiCtrlTypeVo.getInnercode().substring(0,4);
            }
        }

        SqlBuilder wherePart = new SqlBuilder();
        wherePart.append(" dr = 0 and innercode", topInnercode);

        BusictrlTypeVO[] topBusictrlTypes = (BusictrlTypeVO[])getService().queryByCondition(BusictrlTypeVO.class, wherePart.toString());

        if(topBusictrlTypes == null || topBusictrlTypes.length != 1)
            throw new BusinessException("未查询到业务控制类型#"+pk_busictrltype+"#对应的一级业务控制类型，请检查。");


        return topBusictrlTypes[0];

    }

    /**
     * 根据编码查询业务控制类型对应的顶级业务控制类型编码
     * @param busictrltypecode
     * @return
     * @throws BusinessException
     */
    public static BusictrlTypeVO queryTopBusictrlTypeByCode(String busictrltypecode) throws BusinessException{

        SqlBuilder wherePart = new SqlBuilder();

        wherePart.append(" dr = 0 and code in (select substr(innercode,0,4) from "+BusictrlTypeVO.getDefaultTableName()+" where dr = 0");
        wherePart.append(" and code",busictrltypecode);
        wherePart.append(")");

        BusictrlTypeVO[] topBusictrlTypes = (BusictrlTypeVO[])getService().queryByCondition(BusictrlTypeVO.class, wherePart.toString());

        if(topBusictrlTypes == null || topBusictrlTypes.length != 1)
            throw new BusinessException("未查询到业务控制类型#"+busictrltypecode+"#对应的一级业务控制类型，请检查。");


        return topBusictrlTypes[0];

    }

    /**
     * 获取精度
     * @param pk_org
     * @param busiscenemode
     * @return
     */
    public static Integer getDigit(String pk_org,String busiscenemode){

        try{

            Integer currdigit = 2;

            if(pk_org == null || "".equals(pk_org)){
                return 2;
            }

            CurrtypeVO currtypeVO = getCurrtypeByOrg(pk_org);
            if (Objects.isNull(currtypeVO)) {
                return null;
            }

            if(BusisceneModeEnum.AMOUNT.toStringValue().equals(busiscenemode)) {
                currdigit = currtypeVO.getCurrdigit();
            }else if(BusisceneModeEnum.PRICE.toStringValue().equals(busiscenemode)) {
                currdigit = currtypeVO.getUnitcurrdigit();
            }

            return currdigit;

        }catch(Exception e){
            Logger.error(e.getMessage());
            return 2;
        }

    }

    public static String getMessageTitle(BusiConfigVO busiConfigVo){

        StringBuilder mesTitle = new StringBuilder();

        mesTitle.append("业务控制平台");

        try {

            if(busiConfigVo != null) {

                String busiscene = BusisceneEnum.valueOf(BusisceneEnum.class, busiConfigVo.getBusiscene()).getName();
                String busiscenemode = BusisceneModeEnum.valueOf(BusisceneModeEnum.class, busiConfigVo.getBusiscenemode()).getName();

                mesTitle.append("[");
                mesTitle.append(busiscene);
                mesTitle.append("-");
                mesTitle.append(busiscenemode);
                mesTitle.append("]");

            }

        }catch(Exception e) {

            Logger.error(e);

        }

        mesTitle.append("\n");

        return mesTitle.toString();

    }

    public static CurrtypeVO getCurrtypeByOrg(String pk_org) {
        String pk_standardcurr = CurrencyRateUtilHelper.getInstance().getLocalCurrtypeByOrgID(pk_org);
        CurrtypeVO currtype = CurrtypeQuery.getInstance().getCurrtypeVO(pk_standardcurr);
        if (Objects.nonNull(currtype)) {
            return currtype;
        }else {
            return null;
        }
    }

    private static IUifService service;
    public static IUifService getService() throws UifException {
        if (service == null)
            try {
                service = (IUifService) NCLocator.getInstance().lookup(IUifService.class.getName());
            } catch (ComponentException e) {
                Logger.warn("can't find " + e.getComponentName(), (Throwable) e);
                throw new UifException();
            }
        return service;
    }

}
